import java.io.*
import java.net.ServerSocket
import java.net.Socket
import java.util.concurrent.CountDownLatch
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.text.StringBuilder

/**
 * 客户端测试上传速度流程：
 *    1、客户端给服务器发送int类型值9981表示要传文件。
 *    2、客户端给服务器发送long类型的文件大小告知即将发送的文件大小。
 *    3、客户端给服务器发送文件
 *
 * 客户端测试下载速度流程，跟上传流程一样，只不过是反过来：
 *    1、服务器给客户端发送int类型值9981表示要传文件。
 *    2、服务器给客户端发送long类型的文件大小告知即将发送的文件大小。
 *    3、服务器给客户端发送文件
 *
 * 服务器端返回结果给客户端
 *    1、服务器端接收客户端文件和发送文件给客户端
 *    2、服务器端等待客户端发送int类型值1899表示客户端完成了上传和下载操作了
 *    3、服务器端把结果发给客户端
 */
private const val IS_LOCAL = true
private const val IS_USE_BIG_FILE = true
val FILE_PATH = if (IS_LOCAL) {
    if (IS_USE_BIG_FILE) {
        "D:\\000\\kongfu.mp4"
    } else {
        "D:\\000\\test.mp4"
    }
} else {
    "test.mp4"
}

fun main() {
    val serverSocket = ServerSocket(6601)
    val stringBuild = StringBuilder()
    printMessage(stringBuild, "测速服务器开始运行...")
    val threadPool = Executors.newFixedThreadPool(2)
    while (true) {
        val socket = serverSocket.accept() // 此方法是阻塞式的，如果没有客户联进来，这里就一直等着。
        // 设置socket.getInputStream().read()读取数据的超时时间为10秒
        // 如果read()的时候对方没发数据过来就会一直阻塞，直到达到超时时间抛出超时异常
        // write()没有超时说法，因为对方没有读取数据，我们依旧可以立马把数据发出现
        // 经测试，如果对方一直不调用read，可以连续writ() 2.18MB，然后write()函数才开始阻塞
        socket.soTimeout = 10 * 1000

        try {
            processSocket(socket, stringBuild, threadPool)
        } catch (e: Exception) {
            printMessage("服务器端处理socket时出现异常，${e.javaClass.simpleName}: ${e.message}")
            e.printStackTrace()
        } finally {
            try {
                socket.close()
                printMessage("服务器端已关闭${socket.inetAddress.hostAddress}:${socket.port}连接")
            } catch (e: Exception) {
                printMessage("服务器端关闭socket时出现异常，${e.javaClass.simpleName}:${e.message}")
                e.printStackTrace()
            }
        }
    }
}

private fun processSocket(socket: Socket, stringBuild: StringBuilder, threadPool: ExecutorService) {
    val inputStream = socket.getInputStream()
    val outputStream = socket.getOutputStream()
    val receiveSb = StringBuilder(stringBuild)
    val sendSb = StringBuilder(stringBuild)
    val sourceAddress = "${socket.inetAddress.hostAddress}:${socket.port}"
    printMessage(receiveSb, "服务器收到${sourceAddress}连接")

    val dis = DataInputStream(inputStream)
    var flag = dis.readInt()
    if (flag != 9981) {
        printMessage(receiveSb, "${sourceAddress}是一个非法连接，毙了它！")
        return
    }

    printMessage(receiveSb, "${sourceAddress}是正常的测速请求")

    // 请求合法，开启两个线程测速
    val countDownLatch = CountDownLatch(2) // 用于等待发送和接收线程的计数器
    threadPool.execute(Receiver(inputStream, receiveSb, countDownLatch)) // 一个线程接收
    threadPool.execute(Sender(outputStream, sendSb, countDownLatch))     // 一个线程发送

    // 等待接收和发送的线程结束再继续往下走
    countDownLatch.await()

    // 客户端发送1899表示客户端的上传和下载操作已经完成了，可以把服务器的结果给客户端了
    flag = dis.readInt()
    if (flag == 1899) {
        var receiverReport = receiveSb.toString()
        if (receiverReport.endsWith("\n")) {
            receiverReport = receiverReport.substring(0, receiverReport.lastIndexOf("\n"))
        }

        var sendReport = sendSb.toString()
        if (sendReport.endsWith("\n")) {
            sendReport = sendReport.substring(0, sendReport.lastIndexOf("\n"))
        }

        val reports = "服务器端上传报告：\n${receiverReport}\n\n服务器端下载报告：\n${sendReport}"
        println()
        printMessage("服务器测速结果：\n$reports")
        println()
        DataOutputStream(outputStream).writeUTF(reports)
        printMessage("来自${sourceAddress}的测速请求已结束！")
    } else {
        printMessage("${sourceAddress}出现异常，读取到未知flag: $flag")
    }
}

